#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>
#include <functional>
#include "Socket.hpp"

using namespace SocketModule;

// 实现自定义网络版本的计算器

// client -> server
class Request
{
public:
    Request() {};
    Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper)
    {
    }
    std::string Serialize() // 序列化，就是把结构化数据转换为序列化数据（字符串）
    {
        std::string s;
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::FastWriter writer;
        s = writer.write(root);
        return s;
    }
    bool Deserialize(std::string &in) // 反序列化
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if (ok)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }

        return ok;
    }
    int X() { return _x; }
    int Y() { return _y; }
    char Oper() { return _oper; }
    ~Request() {};

private:
    int _x;
    int _y;
    char _oper;
};

// server -> client
class Response
{
public:
    Response() {}
    Response(int result, int code) : _result(result), _code(code)
    {
    }

    std::string Serialize() // 序列化，就是把结构化数据转换为序列化数据（字符串）
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        Json::FastWriter writer;
        return writer.write(root);
    }
    bool Deserialize(std::string &in) // 反序列化
    {
        Json::Value root;
        Json::Reader reader;
        bool ok = reader.parse(in, root);
        if (ok)
        {
            _result = root["result"].asInt();
            _code = root["code"].asInt();
        }

        return ok;
    }
    void ShowResult()
    {
        std::cout << "运算结果是：" << _result << " [" << _code << "]" << std::endl;
    }
    ~Response() {}
    void SetResult(int res)
    {
        _result = res;
    }
    void SetCode(int code)
    {
        _code = code;
    }

private:
    int _result; // 只靠结果不能判断出是正确的值还是异常的值
    int _code;   // 0:success  1 2 3 4 :表示不同的异常情况
};

// 必须保证是完整的，所以需要自己设置一下
const std::string sep = "\r\n";
using func_t = std::function<Response(Request &req)>;
class Protocol
{
public:
    Protocol() {}
    Protocol(func_t func) : _func(func)
    {
    }
    std::string Encode(const std::string jsonstr)
    {
        // 50\r\n{"x": 10,"y": 20,"oper": '+'}\r\n
        std::string len = std::to_string(jsonstr.size());
        // 应用层封装报头
        return len + sep + jsonstr + sep;
    }

    // 50
    // 50\r\n
    // 50\r\n{"x": 10,"y": 20,"oper": '+'}\r\n50\r\n{"x": 10,"y": 20,"oper": '+'}\r\n
    // 读的可能是上面的任意一种，
    // 1.判断报文完整性
    // 2.如果至少包含一个完整请求，提取它，从缓冲区移除它，方便处理下一个
    bool Decode(std::string &buffer, std::string *package)
    {
        ssize_t pos = buffer.find(sep);
        if (pos == std::string::npos)
        {
            return false; // 重新读，让调用方法继续读
        }
        // 找到分隔符了，说明数字有了
        std::string package_len_str = buffer.substr(0, pos);
        int package_len_int = std::stoi(package_len_str);

        // 有报文长度了（前面的数字）但是一定有完整的报文吗？
        int target_len = package_len_str.size() + package_len_int + 2 * sep.size();
        if (buffer.size() < target_len)
        {
            return false; // 读取的长度，小于一个完整报文的长度，返回继续读
        }
        // 到这里说明一定有至少一个完整的报文
        *package = buffer.substr(pos + sep.size(), package_len_int);
        buffer.erase(0, target_len); // 在把刚刚读的整个报文移除
        return true;
    }

    void GetRequest(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        // 读取
        std::string buffer_queue;
        while (true)
        {
            int n = sock->Recv(&buffer_queue);
            std::cout << "----------request_buffer---------------" << std::endl;
            std::cout << buffer_queue << std::endl;
            std::cout << "----------------------------------------" << std::endl;
            if (n > 0)
            {
                std::string json_package;
                // 1.读上来的buffer，不一定是完整的报文，所以就需要上面的写的协议
                while (Decode(buffer_queue, &json_package))
                {   
                    // if (!ret)
                    // {
                    //     continue; // 报文不完整，返回继续读
                    // }
                    std::cout << "----------request_json---------------" << std::endl;
                    std::cout << json_package << std::endl;
                    std::cout << "----------------------------------------" << std::endl;
                    // 到这里说明读到了一整个报文长度
                    // 2.反序列化
                    Request req;
                    bool ok = req.Deserialize(json_package);
                    if (!ok)
                        continue;

                    // 3.到这里，说明反序列化成功，得到了结构化的数据
                    // 通过req->resp，完成计算功能
                    Response resp = _func(req);

                    // 4.现在已经有了应答，需要对这个应答进行序列化
                    std::string json_str = resp.Serialize();

                    // 5.序列化了之后，也不能直接发，还要遵循我们自己的协议，添加自定义的长度
                    std::string send_str = Encode(json_str);

                    // 6.直接发送
                    sock->Send(send_str);
                }
            }
            else if (n == 0)
            {
                LOG(LogLevel::INFO) << "client: " << client.StringAddr() << "Quit!";
                break;
            }
            else
            {
                LOG(LogLevel::WARING) << "client: " << client.StringAddr() << " recv error!";
                break;
            }
        }
    }
    bool GetResponse(std::shared_ptr<Socket> &client, std::string &resp_buffer, Response *resp)
    {
        // 面向字节流
        while (true)
        {
            int n = client->Recv(&resp_buffer);
            if (n > 0)
            {
                std::cout << "----------resp_buffer string---------------" << std::endl;
                std::cout << resp_buffer << std::endl;
                std::cout << "----------------------------------------" << std::endl;
                std::string json_package;
                // 1.读上来的buffer，不一定是完整的报文，所以就需要上面的写的协议
                // bool ret = Decode(resp_buffer, &json_package);
                // if (!ret)
                // {
                //     continue; // 报文不完整，返回继续读
                // }
                while (Decode(resp_buffer, &json_package))
                {
                    std::cout << "----------response json---------------" << std::endl;
                    std::cout << json_package << std::endl;
                    std::cout << "----------------------------------------" << std::endl;

                    std::cout << "----------resp_buffer string---------------" << std::endl;
                    std::cout << resp_buffer << std::endl;
                    std::cout << "----------------------------------------" << std::endl;
                    // 2.到这里了说明一定有完整的报文
                    // 2.反序列化
                    resp->Deserialize(json_package);
                    resp->ShowResult();
                }
                return true;
            }
            else if (n == 0)
            {
                std::cout << "server quit" << std::endl;
                return false;
            }
            else
            {
                std::cout << "recv error" << std::endl;
                return false;
            }
        }
    }
    std::string BuildRequestString(int x, int y, char oper)
    {
        // 1.构建一个完整的请求
        Request req(x, y, oper);
        std::string json_req = req.Serialize(); // 先序列化，返回的是字符串

        //.1添加日志
        std::cout << "----------json_req string---------------" << std::endl;
        std::cout << json_req << std::endl;
        std::cout << "----------------------------------------" << std::endl;

        // 2.构建完整的报头，就是上面的那个加数字的格式
        return Encode(json_req);
    }
    ~Protocol()
    {
    }

private:
    // Request _req;
    // Response _resp;
    func_t _func;
};